Skip to content

Conversation

@ikripaka
Copy link
Collaborator

@ikripaka ikripaka commented Jan 9, 2026

Replace manual duration parsing with humantime
Fixes #38 and dependency issue highlighted by cargo clippy.

Examples of strings to parse can be found here https://docs.rs/humantime/latest/humantime/fn.parse_duration.html.

chore:
* update gitignore
@ikripaka ikripaka self-assigned this Jan 9, 2026
@ikripaka ikripaka requested a review from KyrylR as a code owner January 9, 2026 11:35
@ikripaka ikripaka added enhancement New feature or request greptile Mark this PR to be reviewed by Greptile labels Jan 9, 2026
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

Overview

This PR replaces manual duration parsing with the humantime crate to fix issue #38. The changes improve code maintainability by leveraging an established library rather than implementing custom duration parsing logic.

Core Changes

  1. Dependency Addition: Added humantime = { version = "2.3.0" } to handle duration parsing
  2. Function Replacement: Removed custom parse_duration() function and updated parse_expiry() to use humantime's parser
  3. Error Handling: Added HumantimeParse error variant to properly surface parsing errors
  4. Formatting Consistency: Reformatted Cargo.toml dependencies to use consistent struct syntax

Positive Aspects

  • ✅ Eliminates custom parsing code in favor of a battle-tested library
  • ✅ Humantime supports more flexible duration formats (e.g., "1d2h30m" vs just "1d")
  • ✅ Proper error handling with descriptive error messages
  • ✅ Maintains backward compatibility with Unix timestamp parsing
  • ✅ No breaking changes to public API

Concerns

1. Unrelated Changes Included

The PR includes gitignore changes (config file pattern rename) that are not related to the stated purpose of duration parsing. This violates the principle of focused commits and makes review harder.

2. Missing Test Coverage

The removed parse_duration() function had no explicit tests, but now that the duration parsing logic is inlined in parse_expiry(), there should be dedicated tests for:

  • Relative duration parsing (e.g., "+30d", "+2h")
  • Edge cases and invalid inputs
  • Compatibility with various humantime format strings

3. Mixed Formatting and Functional Changes

Cargo.toml contains both stylistic changes (consistent dependency formatting) and functional changes (adding humantime). These should ideally be separate commits.

Technical Assessment

  • The humantime integration is correct and properly converts to std::time::Duration
  • Error mapping is appropriate with the new HumantimeParse error variant
  • The #[allow(clippy::cast_possible_wrap)] attribute on parse_expiry is correct as it handles the i64 conversion from system time
  • All function signatures remain compatible with existing callers

Commit Quality

The PR violates the custom instruction rule requiring "logical, independent commits that each build and pass unit tests". This is a single commit mixing:

  • Core feature change (humantime integration)
  • Styling/formatting changes (Cargo.toml dependency format consistency)
  • Unrelated configuration changes (gitignore updates)

Confidence Score: 3/5

  • This PR is safe to merge from a functional standpoint with minor concerns about test coverage and commit structure
  • Score of 3 reflects: (1) Core functionality is sound and the humantime integration is correct (+), (2) No breaking changes to public API (+), (3) However, there are organizational issues that violate commit structure rules (-), unrelated gitignore changes that lack justification (-), missing test coverage for the new parse_expiry implementation (-), and mixed formatting/functional changes (-). The code itself would work, but the PR structure and completeness need improvement before merging.
  • .gitignore (needs clarification on why config file pattern changed), crates/cli-client/src/cli/interactive.rs (needs test coverage for parse_expiry)

Important Files Changed

File Analysis

Filename Score Overview
crates/cli-client/Cargo.toml 5/5 Added humantime dependency (2.3.0) and reformatted existing dependencies for consistency. No functional issues detected.
crates/cli-client/src/error.rs 5/5 Added HumantimeParse error variant with proper error message formatting. Error handling integrates well with existing error types.
crates/cli-client/src/cli/interactive.rs 4/5 Replaced custom duration parsing with humantime crate. Core functionality improved but missing test coverage for the new parse_expiry implementation. Error messages slightly changed but remain functional.
.gitignore 2/5 Unrelated changes to gitignore patterns that conflict with the PR's stated purpose. Changes update config file pattern and add duplicate .env entry but lack documentation.

Sequence Diagram

sequenceDiagram
    participant CLI as CLI Code
    participant PE as parse_expiry()
    participant HT as humantime::Duration
    participant Err as Error Handling

    CLI->>PE: Input: expiry string ("+30d" or "1609459200")
    
    alt Unix Timestamp
        PE->>PE: parse::<i64>()
        PE-->>CLI: Return i64 (success)
    else Relative Duration
        PE->>PE: strip_prefix('+')
        PE->>HT: parse::<humantime::Duration>()
        
        alt Parse Success
            HT-->>PE: humantime::Duration
            PE->>PE: Convert to std::time::Duration
            PE->>PE: Calculate: now + duration.as_secs()
            PE-->>CLI: Return i64 (success)
        else Parse Failure
            HT-->>Err: DurationError
            Err-->>PE: Error::HumantimeParse
            PE-->>CLI: Return Error (failure)
        end
    else No Match
        PE-->>CLI: Error::Config (invalid format)
    end
Loading

@greptile-apps
Copy link

greptile-apps bot commented Jan 9, 2026

Additional Comments (1)

crates/cli-client/src/cli/interactive.rs
The parse_expiry function was previously testable through its parse_duration helper, but now that parse_duration has been removed and the logic is inlined using the humantime crate, there are no tests for the new implementation.

Consider adding test cases to verify:

  1. Parsing Unix timestamps still works (e.g., "1609459200")
  2. Parsing durations with humantime works (e.g., "+30d", "+2h", "+1w", "+5m30s")
  3. Invalid formats are properly rejected
  4. Edge cases like "+0s" or very large durations are handled

Example test structure:

#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_parse_expiry_unix_timestamp() {
        // Test unix timestamp parsing
    }
    
    #[test]
    fn test_parse_expiry_relative_duration() {
        // Test relative duration parsing with humantime
    }
}

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: crates/cli-client/src/cli/interactive.rs
Line: 209:231

Comment:
The `parse_expiry` function was previously testable through its `parse_duration` helper, but now that `parse_duration` has been removed and the logic is inlined using the humantime crate, there are no tests for the new implementation. 

Consider adding test cases to verify:
1. Parsing Unix timestamps still works (e.g., "1609459200")
2. Parsing durations with humantime works (e.g., "+30d", "+2h", "+1w", "+5m30s")
3. Invalid formats are properly rejected
4. Edge cases like "+0s" or very large durations are handled

Example test structure:
```rust
#[cfg(test)]
mod tests {
    use super::*;
    
    #[test]
    fn test_parse_expiry_unix_timestamp() {
        // Test unix timestamp parsing
    }
    
    #[test]
    fn test_parse_expiry_relative_duration() {
        // Test relative duration parsing with humantime
    }
}
```

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

@ikripaka
Copy link
Collaborator Author

ikripaka commented Jan 9, 2026

@greptile review the PR according to the CONTRIBUTION.md

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Greptile Overview

Greptile Summary

Summary

This PR replaces the manual duration parsing logic with the humantime crate, addressing issue #38. The changes include:

  1. Main Implementation Change (commit e836a8e): Replaced the custom parse_duration function with humantime::Duration parsing in the parse_expiry function. The new implementation supports more flexible duration formats (e.g., "+30d", "+2h", "+1w", "+45min", "+1d2h").

  2. Dependency Updates (commit 60aa87b):

    • Added humantime 2.3.0 dependency
    • Updated workspace dependencies: contracts and cli-helper revision to "94993a0", simplicityhl-core version to 0.3.4
    • Updated crates/signer/src/lib.rs to use hash_script instead of hash_script_pubkey (breaking API change in dependency)
  3. Test Coverage: Added 9 new test cases covering:

    • Unix timestamp parsing (including zero and large values)
    • Relative duration parsing (days, hours, weeks, minutes, combined units)
    • Error cases (invalid formats, invalid durations, negative durations)

Architecture

The implementation maintains backward compatibility by still supporting Unix timestamp input, while extending functionality to accept relative durations with the + prefix. Error handling properly propagates humantime parsing errors through a new HumantimeParse error variant.

Concerns

  1. Test Timing Race Condition: The new tests contain a potential timing issue where two current_timestamp() calls within a test could span a second boundary, causing assertion failures. While unlikely in practice, the tests could be more robust.

  2. Commit Structure: The PR follows a good logical commit structure with independent, self-contained changes.

Confidence Score: 3/5

  • PR is safe to merge after addressing the flaky test implementation, which could fail under rare timing conditions.
  • The PR successfully implements the intended feature (replacing manual duration parsing with humantime) and includes comprehensive test coverage. However, the new test cases have a potential race condition between two current_timestamp() calls that could cause tests to fail if a second boundary is crossed between calls. While this is unlikely in practice, it represents a code quality issue that should be addressed before merging. The dependency updates appear consistent with the functionality changes. The commit structure is logical and follows best practices.
  • crates/cli-client/src/cli/interactive.rs - The test cases for parse_expiry (lines 479-517) should be refactored to avoid the timing race condition.

Important Files Changed

File Analysis

Filename Score Overview
crates/cli-client/src/cli/interactive.rs 3/5 Replaced manual duration parsing with humantime crate. Tests added for parse_expiry function but may have timing issues due to race condition between multiple current_timestamp() calls.
crates/cli-client/src/error.rs 5/5 Added HumantimeParse error variant to handle duration parsing errors from humantime crate. Properly formatted error message with both the input string and error details.
crates/cli-client/Cargo.toml 5/5 Added humantime 2.3.0 dependency and reformatted dependency entries for consistency. No issues identified.
crates/signer/src/lib.rs 4/5 Updated import and function call from hash_script_pubkey to hash_script, passing address.script_pubkey() instead. Appears to match version update in workspace dependencies.

Sequence Diagram

sequenceDiagram
    participant User
    participant parse_expiry
    participant humantime
    participant current_timestamp
    
    User->>parse_expiry: parse_expiry("+30d")
    
    Note over parse_expiry: Try parse as i64
    
    alt Not a valid i64
        parse_expiry->>parse_expiry: Check for '+' prefix
        
        alt Has '+' prefix
            parse_expiry->>humantime: parse::<humantime::Duration>("30d")
            humantime-->>parse_expiry: Duration(2592000s)
            
            parse_expiry->>current_timestamp: Get current time
            current_timestamp-->>parse_expiry: now (seconds since epoch)
            
            parse_expiry->>parse_expiry: now + 2592000s
            parse_expiry-->>User: Ok(expiry_timestamp)
        else No '+' prefix
            parse_expiry-->>User: Err(Config("Invalid expiry format..."))
        end
    else Valid i64
        parse_expiry-->>User: Ok(timestamp)
    end
Loading

chore:
* add some tests for parse_expiry
* fix hash script dependency error
@ikripaka
Copy link
Collaborator Author

@greptile review the PR according to the CONTRIBUTION.md

@greptile-apps
Copy link

greptile-apps bot commented Jan 11, 2026

Greptile Overview

Greptile Summary

This PR replaces manual duration parsing with the humantime crate, addressing issue #38. The changes improve the user experience by supporting more flexible duration formats (e.g., "1d2h", "45min") instead of the previous single-unit format (e.g., "30d", "2h").

Key Changes

Duration Parsing Enhancement:

  • Removed the custom parse_duration() function that only supported single-unit durations
  • Integrated humantime crate (v2.3.0) for richer duration parsing
  • The parse_expiry() function now supports:
    • Unix timestamps (unchanged): "1704067200"
    • Simple durations: "+30d", "+2h"
    • Complex durations: "+1d2h", "+45min", "+5m30s"

Dependency Updates:

  • Added humantime = "2.3.0" to cli-client dependencies
  • Bumped simplicityhl-core from 0.3.3 to 0.3.4
  • Updated simplicity-contracts git dependency revisions to 94993a0

API Migration:

  • Updated crates/signer/src/lib.rs to use hash_script(&address.script_pubkey()) instead of deprecated hash_script_pubkey(&address) due to the simplicityhl-core upgrade

Testing:

  • Added comprehensive test coverage for parse_expiry() including:
    • Unix timestamps (zero and positive values)
    • Relative durations (days, hours, weeks, minutes, combined)
    • Invalid formats and error handling
    • Edge cases like negative durations

Minor Changes:

  • Simplified .gitignore patterns (tmp/.env.env, config file naming)
  • Formatted dependency declarations in Cargo.toml for consistency

Functional Impact

The change is backward compatible for existing usage patterns while adding new capabilities. Users can continue using the old format ("+30d") or take advantage of more expressive formats ("+1week2days"). The error handling has been improved with a dedicated HumantimeParse error variant that provides clear feedback.

Confidence Score: 4/5

  • This PR is safe to merge with minor caveats - the main functionality is well-tested and the changes are straightforward
  • Score of 4 reflects a well-implemented change with comprehensive testing, but with one style concern about potential integer overflow in extreme edge cases. The humantime integration is clean, error handling is proper, and backward compatibility is maintained. The dependency bump is necessary and correctly implemented alongside the API migration. The only issue is a theoretical overflow scenario that's astronomically unlikely in practice (durations > 292 billion years).
  • Pay attention to crates/cli-client/src/cli/interactive.rs - specifically the u64 to i64 cast on line 225, though this is a minor style concern rather than a critical bug

Important Files Changed

File Analysis

Filename Score Overview
Cargo.toml 4/5 Bumps simplicityhl-core from 0.3.3 to 0.3.4 and updates git dependency revisions. Required for hash_script API change in signer crate.
crates/cli-client/src/cli/interactive.rs 4/5 Replaces manual duration parsing with humantime crate. Main logic is sound, but has potential integer overflow for extremely large durations (u64 to i64 cast). Comprehensive tests added.
crates/cli-client/src/error.rs 5/5 Adds new error variant HumantimeParse for humantime::DurationError. Properly structured with descriptive error message.
crates/signer/src/lib.rs 5/5 Updates to use hash_script instead of deprecated hash_script_pubkey due to simplicityhl-core 0.3.4 upgrade. Passes script_pubkey() directly to hash_script.

Sequence Diagram

sequenceDiagram
    participant User
    participant CLI as CLI Command
    participant ParseExpiry as parse_expiry()
    participant Humantime as humantime crate
    participant Timestamp as current_timestamp()

    User->>CLI: Provide expiry string (e.g., "+30d" or "1704067200")
    CLI->>ParseExpiry: parse_expiry(expiry_str)
    
    alt Unix Timestamp Format
        ParseExpiry->>ParseExpiry: Try parse as i64
        ParseExpiry-->>CLI: Return timestamp
    else Relative Duration Format (starts with '+')
        ParseExpiry->>ParseExpiry: Strip '+' prefix
        ParseExpiry->>Timestamp: Get current time
        Timestamp-->>ParseExpiry: current_timestamp (i64)
        ParseExpiry->>Humantime: Parse duration string
        alt Valid Duration
            Humantime-->>ParseExpiry: Duration object
            ParseExpiry->>ParseExpiry: Convert to seconds (u64)
            ParseExpiry->>ParseExpiry: Cast to i64 (with cast_possible_wrap)
            ParseExpiry->>ParseExpiry: Add to current timestamp
            ParseExpiry-->>CLI: Return future timestamp
        else Invalid Duration
            Humantime-->>ParseExpiry: DurationError
            ParseExpiry-->>CLI: Return Error::HumantimeParse
        end
    else Invalid Format
        ParseExpiry-->>CLI: Return Error::Config
    end
    
    CLI->>CLI: Use timestamp for contract expiry
Loading

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 file reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@KyrylR KyrylR removed the greptile Mark this PR to be reviewed by Greptile label Jan 12, 2026
KyrylR
KyrylR previously approved these changes Jan 12, 2026
Copy link
Collaborator

@KyrylR KyrylR left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 5a16582

@KyrylR KyrylR force-pushed the feature/humantime branch from 5a16582 to dc44856 Compare January 12, 2026 13:49
@KyrylR KyrylR merged commit 1c119ff into main Jan 12, 2026
1 check passed
@greptile-apps
Copy link

greptile-apps bot commented Jan 12, 2026

Required label not found on this PR.

@KyrylR KyrylR deleted the feature/humantime branch January 12, 2026 13:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Change parse_duration onto parsing using humantime

3 participants